package org.j4me.deviceinfo.data;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

public class DeviceDb {
	private static DeviceDb _db;
	private String _fileName;
	private Date _lastModified;
	
	static Logger _logger= Logger.getLogger(DeviceDb.class);

	public DeviceDb(String fileName) {
		_fileName = fileName;
	}

	public void load() {
		FileInputStream in = null;
		SAXReader reader = new SAXReader();
		try {
			in = new FileInputStream(_fileName);
			Document db = reader.read(in);
			Node node = db.selectSingleNode("/devices");
			Iterator<Element> brands = node.selectNodes("brand").iterator();
			while (brands.hasNext()) {
				Element brandElt = brands.next();
				Brand b = new Brand(brandElt);
				if (_brands.get(b.getName()) != null)
					b = _brands.get(b.getName());
				else
					_brands.put(b.getName(), b);
				Iterator<Element> it = brandElt.selectNodes("model").iterator();
				while (it.hasNext()) 
					b.addModel(new Model(b,it.next()));
				
			}
			_lastModified = new Date( new File(_fileName).lastModified());
		} catch (DocumentException e) {
			_logger.fatal("Load DB : Xml error", e);
		} catch (FileNotFoundException e) {
			_logger.fatal("Load DB : File error", e);
		} finally {
			if (in != null)
				try {
					in.close();
				} catch (IOException e) {
				}
		}
		 
	}

	Hashtable<String, Brand> _brands = new Hashtable<String, Brand>();

	public Enumeration<Brand> getBrands() {
		return _brands.elements();
	}

	public Enumeration<String> getBrandNames() {
		return _brands.keys();
	}

	public Brand getBrand(String userAgent) {
		return _brands.get(userAgent);
	}

	public void addDevice(Device model) {
		
		Brand brand = _brands.get(model.getBrand());
		if (brand == null) {
			brand = new Brand(model.getBrand());
			_brands.put(brand.getName(), brand);
		}
		brand.addDevice(model);
	}

	public static DeviceDb factory(String fileName) {
		if (_db == null) {
			_db = new DeviceDb(fileName);
			_db.load();
		}
		return _db;
	}
	
	public static DeviceDb getInstance()
	{
		DeviceDb.factory("/home/tomcat/j4me/devices.xml");
		return _db;
	}

	public void save() {
		
		FileWriter fw = null;
		try {
			fw = new FileWriter(_fileName);
			print(fw);
			_lastModified = new Date();
		} catch (IOException e) {
		} finally {
			
			try {
				fw.close();
			} catch (Exception e) {
			}
		}
	}
	public void print (Writer output ) {
		Document doc = toXmlDocument();
		OutputFormat utf = new OutputFormat();
		utf.setEncoding("UTF-8");
		utf.setSuppressDeclaration(false);
		utf.setIndent(true);
		utf.setNewLineAfterDeclaration(false);
		utf.setNewlines(true);
		utf.setTrimText(true);
		XMLWriter writer = null;
		FileWriter fw = null;
		try {
			writer = new XMLWriter(output, utf);
			writer.write(doc);
		} catch (IOException e) {
		} finally {
			try {
				writer.close();
			} catch (Exception e) {
			}
		}
	}
	public  Document toXmlDocument() {
		Document document = DocumentHelper.createDocument();
		Element root = document.addElement("devices");
		Enumeration<Brand> brands = getBrands();
		while (brands.hasMoreElements()) {
			Brand brand = (Brand) brands.nextElement();
			brand.addXmlNode(root);
			
		}
		return document;
	}
	
	
	public int getBrandCount()
	{
		return _brands.size();
	}

	public int getModelCount()
	{
		int count = 0;
		Enumeration<Brand> brands = getBrands();
		while (brands.hasMoreElements()) {
			count += brands.nextElement().getModelCount();
			
		}
		return count;
	}
	public int getDeviceCount()
	{
		int count = 0;
		Enumeration<Brand> brands = getBrands();
		while (brands.hasMoreElements()) {
			count += brands.nextElement().getDeviceCount();
			
		}
		return count;
	}
	public int getHitCount()
	{
		int count = 0;
		Enumeration<Brand> brands = getBrands();
		while (brands.hasMoreElements()) {
			count += brands.nextElement().getHitCount();
			
		}
		return count;
	}

	public Date getLastModified() {
		return _lastModified;
	}

	public static  String encode(String value) {
		StringBuilder bldr = new StringBuilder();
		
		if(value != null)
		for(int offset=0; offset < value.length();)
		{
			int codePoint = value.codePointAt(offset);
			offset += Character.charCount(codePoint);
			
		
			//if(Character.isDefined(codePoint))
			//{
				switch( Character.getType(codePoint))
				{
					
				case Character.CONTROL:
				case Character.UNASSIGNED:
				case Character.PRIVATE_USE:

				case Character.OTHER_SYMBOL:
					bldr.append(toUniCodeString(codePoint));
					break;
					
					default:
						bldr.appendCodePoint(codePoint);
				}
			//}
			//else
				//bldr.append("#U???");
			
		}
		
		return bldr.toString();
		
		
		
	}

	private static String toUniCodeString(int codePoint) {
		String hexa = Integer.toHexString(codePoint).toUpperCase();
		int pad = 4- hexa.length();
		String prefix = "#U";
		for(int i = 0 ; i < pad ; i++)
			prefix += "0";
		return  prefix + hexa;
		
	}
}
